package edu.ucdavis.gwt.gis.client.export;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;

import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.RootPanel;

import edu.ucdavis.cstars.client.layers.LayerInfo;
import edu.ucdavis.cstars.client.restful.LegendInfo;
import edu.ucdavis.cstars.client.symbol.Symbol;
import edu.ucdavis.gwt.gis.client.canvas.CanvasMap;
import edu.ucdavis.gwt.gis.client.canvas.CanvasPoint;
import edu.ucdavis.gwt.gis.client.canvas.CanvasPolygon;
import edu.ucdavis.gwt.gis.client.canvas.CanvasPolyline;
import edu.ucdavis.gwt.gis.client.canvas.CanvasText;
import edu.ucdavis.gwt.gis.client.canvas.CanvasMap.CanvasMapLoadHandler;
import edu.ucdavis.gwt.gis.client.layers.DataLayer;
import edu.ucdavis.gwt.gis.client.layers.FeatureCollectionDataLayer;
import edu.ucdavis.gwt.gis.client.layers.KmlDataLayer;
import edu.ucdavis.gwt.gis.client.layers.MapServerDataLayer;
import edu.ucdavis.gwt.gis.client.layers.DataLayer.DataLayerType;

public class LegendExporter {

	private CanvasMap canvasMap;
	private AbsolutePanel exportPanel = new AbsolutePanel();
	
	public static LegendExporter INSTANCE = new LegendExporter();
	
	private LinkedList<DataLayer> layers = new LinkedList<DataLayer>();
	
	public static int ROW_HEIGHT = 28;
	public static int TEXT_PADDING = 35;
	public static String FONT_COLOR = "#333333";
	
	public LegendExporter() {
		exportPanel.setVisible(false);
		RootPanel.get().add(exportPanel);
	}
	
	public void clearLayers() {
		layers.clear();
	}

	
	public void addLayer(DataLayer dl) {
		layers.add(dl);
	}
	
	
	public void export() {

		if( !Canvas.isSupported() ) {
			Window.alert("Your browser does not support HTML5.  You cannot export the legend.\n Recommend FireFox, Chrome, Safari or Opera");
			return;
		}

		int count = 0;
		int maxTextLength = 0;
		
		for( DataLayer dl: layers ) {
			if( dl.getType() == DataLayerType.MapServer ) {
				JsArray<LayerInfo> infos = ((MapServerDataLayer) dl).getLegendInfo();
				for( int i = 0; i < infos.length(); i++ ) {
					JsArray<LegendInfo> legends = infos.get(i).getLegendInfo();
					if( infos.get(i).getName().length() > maxTextLength ) maxTextLength = infos.get(i).getName().length();
					for( int j = 0; j < legends.length(); j++ ){
						if( legends.get(j).getLabel().length()+TEXT_PADDING > maxTextLength ) maxTextLength = legends.get(j).getLabel().length()+TEXT_PADDING;
						count++;
					}
					count++;
				}
				
				count += 2; // 2 half's for box and one for layer text
				
			} else if ( dl.getType() == DataLayerType.KML ) {
				HashMap<Symbol, String> infos = ((KmlDataLayer) dl).getLayerInfos();
				Iterator<Symbol> i = infos.keySet().iterator();
				while( i.hasNext() ) {
					String name = infos.get(i.next());
					if( name.length()+TEXT_PADDING > maxTextLength ) maxTextLength = name.length()+TEXT_PADDING;
					count++;
				}
				
				count += 2; // 2 half's for box and one for layer text
			}
		}
		
		int canvasWidth = (maxTextLength*5)+TEXT_PADDING;
		int canvasHeight = (count*ROW_HEIGHT)+TEXT_PADDING;
		canvasMap = new CanvasMap(canvasWidth, canvasHeight);
		
		exportPanel.add(canvasMap.getCanvas());
		
		int imgCount = 0;
		int height = ROW_HEIGHT;
		
		for( DataLayer dl: layers ) {
			
			// MAPSERVER
			if( dl.getType() == DataLayerType.MapServer ) {
				JsArray<LayerInfo> infos = ((MapServerDataLayer) dl).getLegendInfo();
				
				canvasMap.addGeometry(new CanvasText(dl.getLabel(), "16px Arial", FONT_COLOR, 5, height+5));
				height += ROW_HEIGHT;
				
				int lineCount = 0;
				for( int i = 0; i < infos.length(); i++ ) {
					JsArray<LegendInfo> legends = infos.get(i).getLegendInfo();
					
					canvasMap.addGeometry(new CanvasText(infos.get(i).getName(), "13px Arial", FONT_COLOR, 5, height));
					
					CanvasPolyline line = new CanvasPolyline("#cccccc");
					line.addPoint(5, height+4);
					line.addPoint(canvasWidth-8, height+4);
					canvasMap.addGeometry(line);
					
					height += ROW_HEIGHT;
					lineCount++;
					
					for( int j = 0; j < legends.length(); j++ ){
						LegendInfo li = legends.get(j);
						
						canvasMap.addGeometry(new CanvasPoint(5, height-16, "data:"+li.getContentType()+";base64,"+li.getImageData()));
						canvasMap.addGeometry(new CanvasText(li.getLabel(), "12px Arial", FONT_COLOR, 45, height));
						
						imgCount++;
						height += ROW_HEIGHT;
						lineCount++;
					}
				}
				

				canvasMap.addGeometry(createBorder(1, height-(lineCount*ROW_HEIGHT)-(ROW_HEIGHT/2), canvasWidth-5, lineCount*ROW_HEIGHT));
				height += ROW_HEIGHT; // for the bottom border 
				
			// KML
			} else if ( dl.getType() == DataLayerType.KML ) {
				HashMap<Symbol, String> infos = ((KmlDataLayer) dl).getLayerInfos();
				
				canvasMap.addGeometry(new CanvasText(dl.getLabel(), "16px Arial", FONT_COLOR, 5, height+5));
				height += ROW_HEIGHT;
				
				int lineCount = 0;
				
				Iterator<Symbol> i = infos.keySet().iterator();
				while( i.hasNext() ) {
					Symbol symbol = i.next();
					String name = infos.get(symbol);
					
					FeatureCollectionDataLayer.renderSymbolOnCanvas(symbol, canvasMap, height-16, 10);
					canvasMap.addGeometry(new CanvasText(name, "12px Arial", FONT_COLOR, 45, height));
					
					imgCount++;
					height += ROW_HEIGHT;
					lineCount++;
				}
				
				canvasMap.addGeometry(createBorder(1, height-(lineCount*ROW_HEIGHT)-(ROW_HEIGHT/2), canvasWidth-5, lineCount*ROW_HEIGHT));
				height += ROW_HEIGHT; // for the bottom border 
				
			}
			
		}
		
		canvasMap.redraw();
		canvasMap.setLoadHandler(new CanvasMapLoadHandler(){
			@Override
			public void onLoad(CanvasMap map) {
				//Window.open(canvasMap.getCanvas().toDataUrl("image/png"), "Legend Export", "");
				ExportLegendPopup.INSTANCE.showLegend(canvasMap.getCanvas().toDataUrl("image/png"));
				exportPanel.clear();
			}
		});	
	}
	
	
	private CanvasPolygon createBorder(double x, double y, double w, double h) {
		CanvasPolygon polygon = new CanvasPolygon("#333333", null);
		polygon.addPoint(x, y);
		polygon.addPoint(x+w, y);
		polygon.addPoint(x+w, y+h);
		polygon.addPoint(x, y+h);
		polygon.addPoint(x, y);
		return polygon;
	}

}
